package com.xbongbong.saas.factory.publicrule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasMenuEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.model.PaasMenuModel;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.CustomerErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.CustomerRuleEntity;
import com.xbongbong.saas.domain.entity.CustomerUserEntity;
import com.xbongbong.saas.domain.entity.RuleCustomerEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.ChildCustomerRuleEnum;
import com.xbongbong.saas.enums.CustomerRuleChildEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.subform.CustomerTeamEnum;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.sys.domain.entity.UserEntity;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 最大拥有客户数规则功能类
 * @author : chy
 * @date 创建时间：2018-5-16 下午6:51:08
 * @version 3.22
 */
@Slf4j
@Component
public class CheckRuleMaxCustomerNum extends AbstractCheckRule implements ICheckRule {
	@Resource
	private CustomerModel customerModel;
	@Resource
	private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
	@Resource
	private EsHelper esHelper;
	@Resource
	private TransferSubFormHelper transferSubFormHelper;
	@Resource
	private PaasMenuModel paasMenuModel;

	private Integer noBack = 1;
	private Integer customerTypeBack = 2;
	private Integer customerImportantDegreeBack = 3;
	private Integer maxImportantDegree = 5;
	@Resource
	private IndexTypeModel indexTypeModel;

	public CheckRuleMaxCustomerNum(){
	}

	@Override
	public boolean canGainCustomer(CustomerRuleEntity rule, String corpid, UserEntity userEntity, Long customerId, int dataIdSize, JSONObject data) throws XbbException {
		//没有规则，不限制客户获取
		if(rule == null || Objects.equals(rule.getStatus(), 0)){
			return true;
		}
		CustomerEntityExt customerEntity;
		if (Objects.isNull(customerId) || Objects.equals(customerId, 0L)) {
			customerEntity = new CustomerEntityExt();
			customerEntity.setData(data);
		} else {
			customerEntity = customerModel.getByKey(customerId, corpid);
		}
		Integer importantDegree = customerEntity.getData().getInteger(CustomerManagementEnum.IMPORTANT_DEGREE.getAttr());

		if(importantDegree == null){
			importantDegree = 0;
		}
		/**
		 * rule.getRuleType() 必然是 CustomerRuleEnum.MAX_CUSTOMER_NUM_RULE.getCode()
		 */
		IOperateRuleValue operateRuleValue = OperateRuleValueFactory.operateRuleValueFactory(rule.getRuleType());
		JSONObject ruleValueJson = (JSONObject) operateRuleValue.toObject(rule);

		//判断超过最大客户拥有数时是否允许捞取
		JSONObject backRuleJson = ruleValueJson.getJSONObject("backRule");
		Integer backType = backRuleJson.getInteger("backType");

		//根据客户状态自动退回     根据客户重要程度自动退回

		if(Objects.equals(backType, customerTypeBack) || Objects.equals(backType, customerImportantDegreeBack)){
			return true;
		}

		if(!Objects.equals(backType, noBack)){
			throw new XbbException(CustomerErrorCodeEnum.API_ERROR_201032);
		}

		Integer type = ruleValueJson.getInteger("type");

		Integer contract = ruleValueJson.getInteger("contract");
		Integer opportunity = ruleValueJson.getInteger("opportunity");
		List<String> typeNotIn = JSON.parseArray(ruleValueJson.getJSONArray("customerStatus").toJSONString(), String.class);

		if (notBackCustomer(customerEntity, contract, opportunity, typeNotIn)) {
			return true;
		}
		List<Long> labelNotIn = null;
		if (ruleValueJson.containsKey("label")) {
			labelNotIn = JSON.parseArray(ruleValueJson.getJSONArray("label").toJSONString(), Long.class);
		}
		labelNotIn = Objects.isNull(labelNotIn) ? new ArrayList<>() : labelNotIn;

		if (notBackClue4Label(customerEntity, labelNotIn)) {
			return true;
		}

		if (Objects.equals(type, CustomerRuleChildEnum.LABEL.getCode())) {
			Map<Long, Integer> minMap = getMinDayMap(ruleValueJson.getJSONArray("restrict"), userEntity);
			String labelStr = customerEntity.getData().getString(CustomerManagementEnum.LABEL.getAttr());
			List<Long> labels = JSON.parseArray(labelStr, Long.class);
			labels = Objects.isNull(labels) ? new ArrayList<>() : labels;
			if (CollectionsUtil.isNotEmpty(labels)) {
				labels.removeAll(labelNotIn);
			}
			Iterator<Map.Entry<Long, Integer>> iterator = minMap.entrySet().iterator();
			while (iterator.hasNext()) {
				Map.Entry<Long, Integer> next = iterator.next();
				Long key = next.getKey();
				if (labelNotIn.contains(key) || !labels.contains(key)) {
					// 勾选的不退回的标签或当前线索的标签不一样的都去掉
					iterator.remove();
				}
			}

			return getCustomerCountByLabels(corpid, userEntity.getUserId(), typeNotIn, labelNotIn, contract, opportunity, minMap);
		}
		//获取当前用户的最小配置
		/**
		 * key:value
		 * {"1":2,"2":6,"3":5}
		 */
		JSONObject minObject = getMinObject(ruleValueJson.getJSONArray("restrict"), userEntity, type);

		Set<String> keySet = minObject.keySet();
		for(String key : keySet){
			Integer minValue = minObject.getInteger(key);
			//所有客户统一设置，或添加的客户重要程度和规则匹配上时
			boolean isAllCustomerSet = Objects.equals(key, "0");
			//importantDegree为0时，对应1的设置（一星及以下）
			boolean importantDegreeNoSet = (Objects.equals(key, "1") && Objects.equals(importantDegree, 0));
			boolean importantDegreeSet = (Objects.equals(key, importantDegree + ""));
			if(isAllCustomerSet || importantDegreeNoSet || importantDegreeSet){
				Integer customerCount = getCustomerCount(corpid, userEntity.getUserId(), typeNotIn, labelNotIn, contract, opportunity, StringUtil.toInt(key, 0));
				if((customerCount + dataIdSize) > minValue){
					return false;
				}
			}
		}
		return true;
	}

	private boolean getCustomerCountByLabels(String corpid, String userId, List<String> typeNotIn, List<Long> labelNotIn, Integer contract, Integer opportunity, Map<Long, Integer> minMap) {
		if (minMap.isEmpty()) {
			return true;
		}
		boolean canGainCustomer = true;
		try {

			Integer del = 0;
			SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
			BoolQueryBuilder boolQueryBuilder = boolQuery();
			Integer count = getCustomerUserIdIn(corpid, userId, contract, opportunity, boolQueryBuilder);
			//解析查询条件
			boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
			boolQueryBuilder.filter(termQuery("del", del));
			if(typeNotIn != null && typeNotIn.size() > 0){
				boolQueryBuilder.filter(boolQuery().mustNot(termsQuery("data." + CustomerManagementEnum.TYPE.getAttr(), typeNotIn)));
			}
			if(labelNotIn != null && labelNotIn.size() > 0){
				boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.LABEL), labelNotIn)));
			}
			boolQueryBuilder.filter(termsQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.LABEL), minMap.keySet()));
			IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
			boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerIndex.getType()));

			//拿固定数据
			sourceBuilder.fetchSource(CustomerManagementEnum.getAttrConnectData(CustomerManagementEnum.LABEL),null);
			sourceBuilder.query(boolQueryBuilder);

			SearchRequest searchRequest = new SearchRequest(customerIndex.getIndex());
			PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, count);
			searchRequest.source(sourceBuilder);
			XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);

			List<PaasFormDataEntityExt> content = esEntities.getContent();
			Map<Long, Integer> realLabelIdAndNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
			for (PaasFormDataEntityExt entityExt : content) {
				String labelStr = entityExt.getData().getString(CustomerManagementEnum.LABEL.getAttr());
				List<Long> labels = JSON.parseArray(labelStr, Long.class);
				if (CollectionsUtil.isEmpty(labels)) {
					continue;
				}
				for (Long label : labels) {
					Integer num = realLabelIdAndNum.get(label);
					if (Objects.isNull(num)) {
						num = 1;
					} else {
						num++;
					}
					realLabelIdAndNum.put(label, num);
				}
			}
			for (Map.Entry<Long, Integer> entry : minMap.entrySet()) {
				Long key = entry.getKey();
				Integer value = entry.getValue();
				Integer num = realLabelIdAndNum.getOrDefault(key, 0);
				if (Objects.nonNull(num) && num >= value) {
					// 如果拥有的数量大约等于配置的数量，那么就超过了拥有最大数了
					canGainCustomer = false;
					break;
				}

			}
		} catch (Exception e) {

		}
		return canGainCustomer;
	}

	/**
	 * 获取客户团队的相关信息
	 * @param corpid 公司id
	 * @param userId 当前分配的人
	 * @param contract 有合同的客户
	 * @param opportunity 有机会的客户
	 * @param boolQueryBuilder
	 * @return 分页数
	 * @throws XbbException
	 */
	public Integer getCustomerUserIdIn(String corpid, String userId, Integer contract, Integer opportunity, BoolQueryBuilder boolQueryBuilder)  throws XbbException{
		Integer count = 10000;
		if (Objects.equals(1, contract) || Objects.equals(1, opportunity)) {
			// 开启“有合同的客户”或者开启“有销售机会的客户”
			List<Long> customerIdIn = getCustomerIdIN(corpid, userId, contract, opportunity);
			boolQueryBuilder.filter(termsQuery("dataId", customerIdIn));
			return customerIdIn.size();
		} else {
			// 团队表和客户表，联表查询
			IndexTypeEnum customerTeamIndex = indexTypeModel.getCustomerTeamIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
			HasChildQueryBuilder hasChildQueryBuilder = esHelper.teamQueryBuilder(customerTeamIndex, corpid, BasicConstant.ONE, Arrays.asList(userId));
			boolQueryBuilder.filter(hasChildQueryBuilder);
		}
		return count;
	}
	/**
	 * @Description:获取客户数
	 * @param corpid 公司id
	 * @param userId 所属人
	 * @param typeNotIn 排除的状态
	 * @param labelNotIn
	 * @param contract 是否排除有合同的客户
	 * @param opportunity 是否排除有机会的客户
	 * @param importantDegreeInt 重要程度（1特殊代表1星及以下）
	 * @return
	 * 创建时间： 2018-5-22 上午11:33:12
	 * 修改时间： 2018-5-22 上午11:33:12 chy
	 * @author chy
	 * @since v3.22
	 * @version v3.22
	 */
	public Integer getCustomerCount(String corpid, String userId, List<String> typeNotIn, List<Long> labelNotIn, Integer contract, Integer opportunity, Integer importantDegreeInt){
		int count = 0;
		try {

			Integer del = 0;
			BoolQueryBuilder boolQueryBuilder = boolQuery();
			getCustomerUserIdIn(corpid, userId, contract, opportunity, boolQueryBuilder);
			//解析查询条件
			boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
			boolQueryBuilder.filter(termQuery("del", del));
			if(typeNotIn != null && typeNotIn.size() > 0){
				boolQueryBuilder.filter(boolQuery().mustNot(termsQuery("data." + CustomerManagementEnum.TYPE.getAttr() + StringConstant.POINT + StringConstant.KEY_WORD, typeNotIn)));
			}

			if(labelNotIn != null && labelNotIn.size() > 0){
				boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.LABEL), labelNotIn)));
			}

			if(importantDegreeInt != null && importantDegreeInt > 0){
				if(Objects.equals(importantDegreeInt, 1)){
					boolQueryBuilder.filter(rangeQuery("data." + CustomerManagementEnum.IMPORTANT_DEGREE.getAttr()).lte(importantDegreeInt));
				}else{
					boolQueryBuilder.filter(termQuery("data." + CustomerManagementEnum.IMPORTANT_DEGREE.getAttr(), importantDegreeInt));
				}
			}
            IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,customerIndex.getType()));
			SearchRequest searchRequest = new SearchRequest(customerIndex.getIndex());
			SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
			sourceBuilder.query(boolQueryBuilder);
			searchRequest.source(sourceBuilder);
			CountRequest countRequest = new CountRequest(searchRequest.indices()[0]);
			countRequest.query(searchRequest.source().query());
			count = Math.toIntExact(xbbElasticsearchRestTemplate.count(countRequest));
		} catch (Exception e) {

		}

		return count;

	}

	public List<Long> getCustomerIdIN(String corpid, String userId, Integer contract, Integer opportunity) throws XbbException {
		// 开启“有合同的客户”或者开启“有销售机会的客户” 才可以调这个方法
		Set<Long> customerIdSet = new HashSet<>();
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
		BoolQueryBuilder filter = boolQuery()
				.filter(termQuery("corpid.keyword", corpid))
				.filter(termQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.USER_ID), userId))
				.filter(termQuery(CustomerTeamEnum.getEsAttr(CustomerTeamEnum.IS_MAIN), 1))
				.filter(termQuery("del", 0));

		//拿固定数据
		IndexTypeEnum customerTeamIndex = indexTypeModel.getCustomerTeamIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

		sourceBuilder.fetchSource(new String[]{CustomerTeamEnum.getAttrConnectData(CustomerTeamEnum.DATA_ID)},null);
		filter.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerTeamIndex.getType()));
		sourceBuilder.query(filter);
		SearchRequest searchRequest = new SearchRequest(customerTeamIndex.getIndex());
		//TODO
		PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 10000);
		searchRequest.source(sourceBuilder);
		XbbAggregatedPage<PaasFormDataEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntity.class);
		List<CustomerUserEntity> userTeamEntities =(List<CustomerUserEntity>) transferSubFormHelper.transferFormDataToUserTeamList(IndexTypeEnum.IDX_SAAS_CUSTOMER_TEAM, esEntities.getContent());
		for(CustomerUserEntity customerUserEntity : userTeamEntities) {
			Long customerId = customerUserEntity.getDataId();
			customerIdSet.add(customerId);
		}

		List<Long> customerIdIn = new ArrayList<>(customerIdSet);

		List<Long> excludeCustomerIdIn = new ArrayList<>();
		excludeCustomerIdIn.addAll(getExcludeCustomerIdInByContract(corpid, customerIdIn, contract));
		excludeCustomerIdIn.addAll(getExcludeCustomerIdInByOpportunity(corpid, customerIdIn, opportunity));

		customerIdIn.removeAll(excludeCustomerIdIn);

		return customerIdIn;
	}

	public Map<Long, Integer> getMinDayMap(JSONArray restrict, UserEntity userEntity) {
		Map<Long, Integer> specialMinDayMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
		Map<Long, Integer> allMinDayMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
		List<Long> deptIds;
		try {
			deptIds = JSONArray.parseArray(userEntity.getDepartment(), Long.class);
		} catch (Exception e) {
			deptIds = new ArrayList<>();
		}
		if (deptIds == null) {
			deptIds = new ArrayList<>();
		}
		List<Integer> roleIds = new ArrayList<>();
		String role = userEntity.getRoleIds();
		if (StringUtil.isNotEmpty(role)) {
			roleIds = StringUtil.roleIdToListInt(role);
		}
		if (roleIds == null) {
			roleIds = new ArrayList<>();
		}
		for(Object restrictObject : restrict){
			JSONObject restrictJson = (JSONObject)restrictObject;
			JSONArray users = restrictJson.getJSONArray("users");
			JSONArray depts = restrictJson.getJSONArray("depts");
			JSONArray roles = restrictJson.getJSONArray("roles");
			List<String> userIdList = new ArrayList<>();
			List<Long> deptIdList = new ArrayList<>();
			List<Integer> roleIdList = new ArrayList<>();
			if (Objects.nonNull(users)) {
				userIdList = JSON.parseArray(users.toJSONString(), String.class);
			}
			if (Objects.nonNull(depts)) {
				deptIdList = JSON.parseArray(depts.toJSONString(), Long.class);
			}
			if (Objects.nonNull(roles)) {
				roleIdList = JSON.parseArray(roles.toJSONString(), Integer.class);
			}
			deptIdList.retainAll(deptIds);
			roleIdList.retainAll(roleIds);
			Boolean scecialConfig = users != null || depts != null || roles != null;
			Boolean configFail = !userIdList.contains(userEntity.getUserId()) && deptIdList.isEmpty() && roleIdList.isEmpty();
			if(scecialConfig && configFail){
				//对于当前用户无效的配置
				continue ;
			}

			JSONArray array = restrictJson.getJSONArray("array");

			stringKey(array, users, depts, roles, specialMinDayMap, allMinDayMap);
		}
		Iterator<Map.Entry<Long, Integer>> it = allMinDayMap.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<Long, Integer> entry = it.next();
			Long key = entry.getKey();

			Integer integer = specialMinDayMap.get(key);
			if (Objects.nonNull(integer)) {
				// 如果某个标签出现在全部和特殊里面，那么去掉全部的标签配置；
				it.remove();
			}
		}
		specialMinDayMap.putAll(allMinDayMap);
		return specialMinDayMap;
	}

	private void stringKey(JSONArray array, JSONArray users, JSONArray depts, JSONArray roles, Map<Long, Integer> specialMinDayMap, Map<Long, Integer> allMinDayMap) {
		for(Object object : array){
			JSONObject jsonObject = (JSONObject)object;
			String key = jsonObject.getString("key");

			List<Long> labels = JSON.parseArray(key, Long.class);

			Integer value = jsonObject.getInteger("value");

			if(users == null && depts == null && roles == null){
				for (Long label : labels) {
					Integer integer = allMinDayMap.get(label);
					if (Objects.isNull(integer)) {
						allMinDayMap.put(label, value);
						continue;
					}
					if (integer < value) {
						allMinDayMap.put(label, integer);
					}
				}
				continue ;
			}

			for (Long label : labels) {
				Integer integer = specialMinDayMap.get(label);
				if (Objects.isNull(integer)) {
					specialMinDayMap.put(label, value);
					continue;
				}
				if (integer < value) {
					specialMinDayMap.put(label, integer);
				}
			}
		}
	}

	/**
	 * 获取需要排除的有机会的客户id
	 * @param corpid
	 * @param customerIdIn 客户id集合
	 * @param opportunity 是否包含机会（1、需要排除有机会的客户 0、不需要排除）
	 * @return
	 * @throws XbbException
	 * 创建时间 2019/8/19 1:47 PM
	 * 修改时间 2019/8/19 1:47 PM
	 * @author chy
	 * @since v1.1.3
	 * @version v1.1.3
	 */
	public List<Long> getExcludeCustomerIdInByOpportunity(String corpid, List<Long> customerIdIn, Integer opportunity) throws XbbException {
		if (!Objects.equals(opportunity, 1)) {
			return new ArrayList<>();
		}
		return getCustomerIdsFromOpportunity(corpid, customerIdIn, 0);
	}

	/**
	 * 获取需要排除的有合同的客户id
	 * @param corpid
	 * @param customerIdIn 客户id集合
	 * @param contract 是否包含合同（1、需要排除有合同的客户 0、不需要排除）
	 * @return
	 * @throws XbbException
	 * 创建时间 2019/8/19 1:47 PM
	 * 修改时间 2019/8/19 1:47 PM
	 * @author chy
	 * @since v1.1.3
	 * @version v1.1.3
	 */
	public List<Long> getExcludeCustomerIdInByContract(String corpid, List<Long> customerIdIn, Integer contract) throws XbbException {

		if (!Objects.equals(contract, 1)) {
			return new ArrayList<>();
		}

		return getCustomerIdsFromContract(corpid, customerIdIn, 0);
	}

	@Override
	public List<RuleCustomerEntity> getBackCustomerList(UserEntity userEntity,
													CustomerRuleEntity rule, List<RuleCustomerEntity> customerList,
													Integer advanceTime) throws XbbException {
		return new ArrayList<>();
	}

	@Override
	public List<RuleCustomerEntity> getBackCustomerList(UserEntity userEntity,
			CustomerRuleEntity rule, List<RuleCustomerEntity> customerList)
			throws XbbException {

		List<RuleCustomerEntity> retList = new ArrayList<>();
		if(rule == null || Objects.equals(rule.getStatus(), 0)){
			return retList;
		}

		IOperateRuleValue operateRuleValue = OperateRuleValueFactory.operateRuleValueFactory(rule.getRuleType());
		Object ruleValueObject = operateRuleValue.toObject(rule);
		JSONObject ruleValueJson = (JSONObject)ruleValueObject;

		//判断退回规则
		JSONObject backRule = ruleValueJson.getJSONObject("backRule");
		Integer backType = backRule.getInteger("backType");
		//不自动退回
		if(Objects.equals(backType, 1)){
			return retList;
		}

		Integer type = ruleValueJson.getInteger("type");

		Integer contract = ruleValueJson.getInteger("contract");
		Integer opportunity = ruleValueJson.getInteger("opportunity");
		List<String> typeNotIn = JSON.parseArray(ruleValueJson.getJSONArray("customerStatus").toJSONString(), String.class);
		List<Long> labelNotIn = null;
		if (ruleValueJson.containsKey("label")) {
			labelNotIn = JSON.parseArray(ruleValueJson.getJSONArray("label").toJSONString(), Long.class);
		}
		labelNotIn = Objects.isNull(labelNotIn) ? new ArrayList<>() : labelNotIn;

		if (Objects.equals(type, CustomerRuleChildEnum.LABEL.getCode())) {

			removeRuleNoBack(userEntity.getCorpid(), customerList, contract, opportunity, typeNotIn);

			removeRuleLabelNoBack(customerList, labelNotIn);

			Map<Long, Integer> minDayMap = getMinDayMap(ruleValueJson.getJSONArray("restrict"), userEntity);
			Iterator<Map.Entry<Long, Integer>> iterator = minDayMap.entrySet().iterator();
			while (iterator.hasNext()) {
				Map.Entry<Long, Integer> next = iterator.next();
				Long key = next.getKey();
				if (labelNotIn.contains(key)) {
					// 勾选的不退回的标签或当前线索的标签不一样的都去掉
					iterator.remove();
				}
			}
			JSONArray sort = backRule.getJSONArray("sort");
			return getBackCustomers(minDayMap, customerList, userEntity.getCorpid(), sort);
		}

		//获取当前用户的最小配置
		/**
		 * key:value
		 * {"1":2,"2":6,"3":5}
		 */
		JSONObject minObject = getMinObject(ruleValueJson.getJSONArray("restrict"), userEntity, type);
		//判断没有移除客户前是否超过最大客户数规则限制
		if(!moreThanRuleNum(userEntity, type, minObject)){
			return retList;
		}
        String corpid = userEntity.getCorpid();
        String userId = userEntity.getUserId();
		removeRuleNoBack(corpid, customerList, contract, opportunity, typeNotIn);
		removeRuleLabelNoBack(customerList, labelNotIn);
		// 获取menuId，用来移除经销商数据
		PaasMenuEntity paasMenuEntity = paasMenuModel.getByAlias4Distributor(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getAlias(), corpid, DistributorMarkEnum.OTHER.getCode());
		Long menuId = paasMenuEntity.getId();
		List<Long> customerIdIn = new ArrayList<>();
		for(RuleCustomerEntity customer : customerList){
			customerIdIn.add(customer.getId());
		}
		//获取需要退回公海池的客户数,记录每种类型的截取信息
		JSONObject moreCountObject = new JSONObject();
		if(Objects.equals(type, ChildCustomerRuleEnum.CUSTOMER_ALL.getCode())) {
			Integer moreCount = 0;
			Integer minCount = (Integer) minObject.get("0");
			Integer count = customerList.size();
			if(minCount != null && count > minCount){
				moreCount = count - minCount;
			}

			JSONObject pageJson = new JSONObject();
			pageJson.put("start", 0);
			pageJson.put("pageNum", moreCount);

			moreCountObject.put("0", pageJson);
		} else if (Objects.equals(type, ChildCustomerRuleEnum.CUSTOMER_IMPORTANT_DEGREE.getCode())){

			for(int i = 1; i < maxImportantDegree + 1; i++){
				Integer moreCount = 0;
				Integer minCount = (Integer) minObject.get(i+"");
				Integer count = customerModel.getMainCustomerCountByUserId(corpid, userId, i);
				if(minCount != null && count > minCount){
					moreCount = count - minCount;
				}
				JSONObject pageJson = new JSONObject();
				pageJson.put("start", 0);
				pageJson.put("pageNum", moreCount);
				moreCountObject.put(i+"", pageJson);
			}
		}

		//获取退回顺序
		String orderField = null;

		JSONArray sort = backRule.getJSONArray("sort");

		List<Integer> sortList = new ArrayList<>();
		if (Objects.nonNull(sort)) {
			sortList = sort.toJavaList(Integer.class);
		}

		//设置排序字段
		if(Objects.equals(backType, customerTypeBack)){
			if(CollectionsUtil.isNotEmpty(sortList)){
				orderField = CustomerManagementEnum.getAttrConnectData(CustomerManagementEnum.TYPE);
			}
		} else if(Objects.equals(backType, customerImportantDegreeBack)) {
			if(CollectionsUtil.isNotEmpty(sortList)){
				orderField = CustomerManagementEnum.getAttrConnectData(CustomerManagementEnum.IMPORTANT_DEGREE);
			}
		}
		//存储时，客户状态、重要程度可能会存0，将0作为其中一个排序
		if (CollectionsUtil.isNotEmpty(sortList)) {
			sortList.add(0, 0);
        }
		if(Objects.equals(type, ChildCustomerRuleEnum.CUSTOMER_ALL.getCode())) {
			JSONObject pageJson = moreCountObject.getJSONObject("0");
			Integer pageNum = null;
			Integer pageSize = null;
			if(pageJson != null){
				pageNum = 1;
				pageSize = pageJson.getInteger("pageNum");
			}
			retList = customerModel.getMainCustomerListByUserId(corpid, userId, null, pageNum, pageSize, orderField, sortList, customerIdIn, menuId);
		} else if (Objects.equals(type, ChildCustomerRuleEnum.CUSTOMER_IMPORTANT_DEGREE.getCode())){
			for(int i = 1; i < maxImportantDegree + 1; i++){
				JSONObject pageJson = moreCountObject.getJSONObject(i+"");
				Integer pageNum = null;
				Integer pageSize = null;
				if(pageJson != null){
					pageNum = 1;
					pageSize = pageJson.getInteger("pageNum");
				}
				retList.addAll(customerModel.getMainCustomerListByUserId(corpid, userId, i, pageNum, pageSize, orderField, sortList, customerIdIn, menuId));
			}
		}
		return retList;
	}

	private List<RuleCustomerEntity> getBackCustomers(Map<Long, Integer> minDayMap, List<RuleCustomerEntity> customerList, String corpid, JSONArray sort) throws XbbException{
		List<RuleCustomerEntity> customers = new ArrayList<>();
		if (minDayMap.isEmpty()) {
			return customers;
		}
		List<Long> clueIdIn = new ArrayList<>();
		for (RuleCustomerEntity clue : customerList) {
			clueIdIn.add(clue.getId());
		}
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
		BoolQueryBuilder boolQueryBuilder = boolQuery();
		IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

		//解析查询条件
		boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
		boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
		boolQueryBuilder.filter(termsQuery("dataId", clueIdIn));
		boolQueryBuilder.filter(termsQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.LABEL), minDayMap.keySet()));
		boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerIndex.getType()));
		List<String> fieldList = Arrays.asList(CustomerManagementEnum.LABEL.getAttr(), CustomerManagementEnum.TYPE.getAttr(), FieldTypeEnum.DATAID.getAlias());
		//拿固定数据
		EsUtil.setFieldList(sourceBuilder, fieldList);
		sourceBuilder.query(boolQueryBuilder);
		SearchRequest searchRequest = new SearchRequest(customerIndex.getIndex());
		PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, clueIdIn.size());
		searchRequest.source(sourceBuilder);

		XbbAggregatedPage<PaasFormDataEntityExt> esEntities =  xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest,PaasFormDataEntityExt.class);

		List<PaasFormDataEntityExt> content = esEntities.getContent();
		Map<String, List<PaasFormDataEntityExt>> entityMap = new LinkedHashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
		for (PaasFormDataEntityExt entityExt : content) {
			String status = entityExt.getData().getString(ClueEnum.CLUE_STATUS.getAttr());
			if (StringUtil.isEmpty(status)) {
				continue;
			}
			List<PaasFormDataEntityExt> orDefault = entityMap.getOrDefault(status, new ArrayList<>());
			orDefault.add(entityExt);
			entityMap.put(status, orDefault);
		}

		List<String> list = JSONArray.parseArray(sort.toJSONString(), String.class);
		// 因为排在上面的优先退回，所以这边倒叙处理，就能实现后面出现的数据退回的概率比前面小
		Collections.reverse(list);
		List<PaasFormDataEntityExt> exts = new ArrayList<>();
		for (String str : list) {
			List<PaasFormDataEntityExt> entityExts = entityMap.get(str);
			if (CollectionsUtil.isNotEmpty(entityExts)) {
				exts.addAll(entityExts);
			}
		}
		List<Long> idIn = new ArrayList<>();
		Long menuId = null;

		Map<Long, Integer> labelIdAndNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
		for (PaasFormDataEntityExt entityExt : content) {
			String status = entityExt.getData().getString(CustomerManagementEnum.TYPE.getAttr());
			if (StringUtil.isEmpty(status)) {
				continue;
			}
			String labelStr = entityExt.getData().getString(CustomerManagementEnum.LABEL.getAttr());
			List<Long> labels = JSON.parseArray(labelStr, Long.class);
			if (CollectionsUtil.isEmpty(labels)) {
				continue;
			}
			for (Long label : labels) {
				Integer num = labelIdAndNum.get(label);
				if (Objects.isNull(num)) {
					num = 1;
				} else {
					num++;
				}
				Integer minNum = minDayMap.get(label);
				if (Objects.nonNull(minNum) && num > minNum) {
					idIn.add(entityExt.getDataId());
					menuId = entityExt.getMenuId();
				}
				labelIdAndNum.put(label, num);
			}
		}

		if (CollectionsUtil.isNotEmpty(idIn) && menuId != null) {
			customers = customerModel.getMainCustomerList4Rule(corpid, idIn, menuId);
		}
		return customers;
	}


	/**
	 * @Description: 判断未移除客户前，拥有客户是否超过规则限制
	 * @param userEntity
	 * @param type
	 * @param minObject
	 * @return
	 * 创建时间： 2018-5-23 下午4:26:41
	 * 修改时间： 2018-5-23 下午4:26:41 chy
	 * @author chy
	 * @since v3.22
	 * @version v3.22
	 */
	private boolean moreThanRuleNum(UserEntity userEntity, Integer type,
			JSONObject minObject) throws XbbException {
		//没有限制
		if(minObject == null){
			return false;
		}
		String corpid = userEntity.getCorpid();
		String userId = userEntity.getUserId();
		if(Objects.equals(type, ChildCustomerRuleEnum.CUSTOMER_ALL.getCode())) {
			Integer minNum = (Integer) minObject.get("0");

			if(minNum == null){
				return false;
			}
			Long startTime = DateTimeUtil.getInt();
			Integer count = customerModel.getMainCustomerCountByUserId(corpid, userId, null);
			String paramStr = "corpid:" + corpid + "userId:" + userId + "importantDegree:" + null;
			if(count > minNum){
				return true;
			}
		} else if(Objects.equals(type, ChildCustomerRuleEnum.CUSTOMER_IMPORTANT_DEGREE.getCode())) {
			Set<String> set = minObject.keySet();
			for(String key : set){
				Integer importantDegree = StringUtil.toInt(key, null);
				Integer minNum = (Integer) minObject.get(key);
				Long startTime = DateTimeUtil.getInt();
				Integer count = customerModel.getMainCustomerCountByUserId(corpid, userId, importantDegree);
				String paramStr = "corpid:" + corpid + "userId:" + userId + "importantDegree:" + importantDegree;
				if(count > minNum){
					return true;
				}
			}
		}
		return false;
	}

	@Override
	public JSONObject customerTypeChage(CustomerRuleEntity rule, List<ItemPoJo> typeItemPoJos) throws XbbException {
		IOperateRuleValue operateRuleValue = OperateRuleValueFactory.operateRuleValueFactory(rule.getRuleType());
		Object ruleValueObject = operateRuleValue.toObject(rule);
		JSONObject ruleValueJson = (JSONObject)ruleValueObject;
		JSONObject backRule = ruleValueJson.getJSONObject("backRule");
		if(backRule == null){
			return null;
		}

		Integer backType = backRule.getInteger("backType");
		if(!Objects.equals(backType, customerTypeBack)){
			return null;
		}

		List<Integer> valueList = new ArrayList<>();
		for(ItemPoJo itemPoJo : typeItemPoJos){
			Integer value = StringUtil.toInt(String.valueOf(itemPoJo.getValue())) ;
			valueList.add(value);
		}

		JSONArray sortEndArray = new JSONArray();
		//将原公海规则设置存在的排序先排序（移除被删除或不启用的客户状态）
		JSONArray sortArray = backRule.getJSONArray("sort");
		for(Object sortObject : sortArray){
			Integer code = (Integer)sortObject;
			//在当前数据字典中
			if(valueList.contains(code)){
				sortEndArray.add(code);
			}
		}

		for(Integer code : valueList){
			if(!sortEndArray.contains(code)){
				sortEndArray.add(code);
			}
		}
		backRule.put("sort", sortEndArray);
		ruleValueJson.put("backRule", backRule);
		return ruleValueJson;
	}


	/**
	 * 是否是不需要退回的线索
	 * @param clueEntity
	 * @param labelNotIn
	 * @return
	 */
	public boolean notBackClue4Label(CustomerEntityExt clueEntity, List<Long> labelNotIn) {
		JSONArray jsonArray = clueEntity.getData().getJSONArray(CustomerManagementEnum.LABEL.getAttr());
		List<Long> labels = null;
		if (CollectionsUtil.isNotEmpty(jsonArray)) {
			labels = JSON.parseArray(jsonArray.toJSONString(), Long.class);
		}
		if (CollectionsUtil.isEmpty(labelNotIn) || CollectionsUtil.isEmpty(labels)) {
			return false;
		}
		labels.retainAll(labelNotIn);
		if (CollectionsUtil.isNotEmpty(labels)) {
			return true;
		}
		return false;
	}
}
